#include "oled.h"
#include "gamefont.h"
#include "stdlib.h"


void oled_drawbmp_block_clear(int bx, int by, int clear_size)
{
    unsigned int i;
    OLED_Set_Pos(bx, by);
    IIC_Start();
    Write_IIC_Byte(0x78);
    IIC_Wait_Ack();
    Write_IIC_Byte(0x40);
    IIC_Wait_Ack();

    for (i = 0; i < clear_size; i++)
    {
        if (bx + i > 128) break;
        Write_IIC_Byte(0x0);
        IIC_Wait_Ack();
    }
    IIC_Stop();
}
// 绘制地面
void OLED_DrawGround()
{
    static unsigned int pos = 0;
    unsigned char speed = 5;
    unsigned int ground_length = sizeof(GROUND);
    unsigned char x;

    OLED_Set_Pos(0, 7);
    IIC_Start();
    Write_IIC_Byte(0x78);
    IIC_Wait_Ack();
    Write_IIC_Byte(0x40);
    IIC_Wait_Ack();
    for (x = 0; x < 128; x++)
    {
        Write_IIC_Byte(GROUND[(x + pos) % ground_length]);
        IIC_Wait_Ack();
    }
    IIC_Stop();

    pos = pos + speed;
    //if(pos>ground_length) pos=0;
}

// 绘制云朵
void OLED_DrawCloud()
{
    static int pos = 128;
    static char height = 0;
    char speed = 3;
    int x;
    int start_x = 0;
    int length = sizeof(CLOUD);
    unsigned char byte;

		// 云朵总是出现在最上面
    //if (pos + length <= -speed) pos = 128;

    if (pos + length <= -speed)
    {
        pos = 128;
        height = rand() % 3;
    }
    if(pos < 0)
    {
        start_x = -pos;
        OLED_Set_Pos(0, 1 + height);
    }
    else
    {
        OLED_Set_Pos(pos, 1 + height);
    }
		
    IIC_Start();
    Write_IIC_Byte(0x78);
    IIC_Wait_Ack();
    Write_IIC_Byte(0x40);
    IIC_Wait_Ack();
    for (x = start_x; x < length + speed; x++)
    {
        if (pos + x > 127) break;
        if (x < length) byte = CLOUD[x];
        else byte = 0x0;

        Write_IIC_Byte(byte);
        IIC_Wait_Ack();
    }
    IIC_Stop();
    pos = pos - speed;
}

// 绘制小恐龙
void OLED_DrawDino()
{
		// 小恐龙的方向。静态变量在程序的生命周期内保持其值。
    static unsigned char dino_dir = 0;
		// 这些是函数内部使用的变量。j用于在循环中迭代，x和y用于表示坐标，byte用于存储要写入的字节。
    unsigned int j = 0;
    unsigned char x, y;
    unsigned char byte;
		int length = sizeof(DINO) / 4;
		// 这两行代码使dino_dir在0和1之间循环，表示小恐龙的两种不同状态或方向
    dino_dir++;
    dino_dir = dino_dir % 2;
		// 这个循环是函数的核心部分，它在OLED屏幕上绘制小恐龙的图像。首先，它设置了OLED的位置，然后开始IIC通信，写入一些特定的字节并等待确认。
		// 然后，它在一个内部循环中，根据dino_dir和当前的x和y值从DINO数组中获取字节，并写入这个字节。
		// 最后，它停止IIC通信。这个过程对每个y值重复两次，这可能表示小恐龙的图像是2行高。
    for(y = 0; y < 2; y++)
    {
        OLED_Set_Pos(16, 6 + y);
        IIC_Start();
        Write_IIC_Byte(0x78);
        IIC_Wait_Ack();
        Write_IIC_Byte(0x40);
        IIC_Wait_Ack();
        for (x = 0; x < length; x++)
        {
            j = y * length + x;
            byte = DINO[dino_dir][j];

            Write_IIC_Byte(byte);
            IIC_Wait_Ack();
        }
        IIC_Stop();
    }
}

// 绘制飞龙
int OLED_DrawFlyDragon(unsigned char reset)
{
		// 控制飞龙移动的速度
    char speed = 5;
		// 静态变量pos，用于存储飞龙的位置。静态变量在程序的生命周期内保持其值。
    static int pos = 128;
    // 静态变量height，用于存储飞龙的高度。
    static int height = 0;
		// 飞龙的方向。静态变量在程序的生命周期内保持其值。
    static unsigned char dragon_dir = 0;
		// 这些是函数内部使用的变量。j用于在循环中迭代，x和y用于表示坐标，byte用于存储要写入的字节。
    unsigned int j = 0;
    unsigned char x, y;
    unsigned char byte;
		// 这两行代码使dino_dir在0和1之间循环，表示飞龙的两种不同状态或方向
    dragon_dir++;
    dragon_dir = dragon_dir % 2;		
		
		// 这些是函数内部使用的变量。start_x用于表示开始的x坐标，length用于存飞龙图像的长度。
    int start_x = 0;
    int length = sizeof(FlyingDragon) / 4;
	
		// 如果飞龙的位置加上其长度小于或等于0，或者收到重置命令，那么清除屏幕上的飞龙，并将飞龙的位置重置为128。
    /*if (pos + length <= 0 || reset == 1)
    {
			oled_drawbmp_block_clear(0, 6, speed);
			pos = 128;
			return 128;
    }*/

		// 这个循环是函数的核心部分，它在OLED屏幕上绘制飞龙的图像。首先，它设置了OLED的位置，然后开始IIC通信，写入一些特定的字节并等待确认。
		// 然后，它在一个内部循环中，根据当前的x和y值从FlyingDragon数组中获取字节，并写入这个字节。
		// 最后，它停止IIC通信。这个过程对每个y值重复两次，这表示飞龙的图像是2行高。
    for(y = 0; y < 2; y++)
    {
      if (pos + length <= -speed)
      {
          pos = 128;
          height = rand() % 3;
      }

      if (pos < 0)
      {
          start_x = -pos;
          OLED_Set_Pos(0, 6 + y + height);
      }
      else
      {
          OLED_Set_Pos(pos, 6 + y  + height);
      }
      IIC_Start();
      Write_IIC_Byte(0x78);
      IIC_Wait_Ack();
      Write_IIC_Byte(0x40);
      IIC_Wait_Ack();
      for (x = start_x; x < length; x++)
      {
          if (pos + x > 127) break;
          j = y * length + x;
          byte = FlyingDragon[dragon_dir][j];
          Write_IIC_Byte(byte);
          IIC_Wait_Ack();
      }
      IIC_Stop();
    }
		// 这行代码清除了飞龙移动后留下的图像，以便在下一帧中重新绘制。
    oled_drawbmp_block_clear(pos + length, 6, speed);
		// 最后，更新飞龙的位置，使其向左移动。
    pos = pos - speed;
		return pos + speed;
}

// 绘制随机出现的仙人掌障碍物
int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset)
{
		// 控制仙人掌移动的速度
    char speed = 5;
		// 静态变量pos，用于存储仙人掌的位置。静态变量在程序的生命周期内保持其值。
    static int pos = 128;
		// 这些是函数内部使用的变量。start_x用于表示开始的x坐标，length用于存储仙人掌图像的长度。
    int start_x = 0;
    int length = 0;

		// 这些是函数内部使用的变量。j用于在循环中迭代，x和y用于表示坐标，byte用于存储要写入的字节。
    //unsigned int i=0, j=0;
    unsigned int  j = 0;
    unsigned char x, y;
    unsigned char byte;
    if (reset == 1)
    {
        pos = 128;
        oled_drawbmp_block_clear(0, 6, speed);
        return 128;
    }
		// 根据ver参数的值，设置仙人掌的长度。这表示有不同大小的仙人掌。
    if (ver == 0) length = 8; //sizeof(CACTUS_1) / 2;
    else if (ver == 1) length = 16; //sizeof(CACTUS_2) / 2;
    else if (ver == 2 || ver == 3) length = 24;

		// 这个循环是函数的核心部分，它在OLED屏幕上绘制仙人掌的图像。首先，它设置了OLED的位置，然后开始IIC通信，写入一些特定的字节并等待确认。
		// 然后，它在一个内部循环中，根据当前的x和y值从CACTUS_2数组中获取字节，并写入这个字节。
		// 最后，它停止IIC通信。这个过程对每个y值重复两次，这可能表示仙人掌的图像是2行高。
    for(y = 0; y < 2; y++)
    {
        if(pos < 0)
        {
            start_x = -pos;
            OLED_Set_Pos(0, 6 + y);
        }
        else
        {
            OLED_Set_Pos(pos, 6 + y);
        }

        IIC_Start();
        Write_IIC_Byte(0x78);
        IIC_Wait_Ack();
        Write_IIC_Byte(0x40);
        IIC_Wait_Ack();

        for (x = start_x; x < length; x++)
        {
            if (pos + x > 127) break;

            j = y * length + x;
            if (ver == 0) byte = CACTUS_1[j];
            else if (ver == 1) byte = CACTUS_2[j];
            else if(ver == 2) byte = CACTUS_3[j];
            else byte = CACTUS_4[j];

            Write_IIC_Byte(byte);
            IIC_Wait_Ack();
        }
        IIC_Stop();
    }
		// 这行代码清除了仙人掌移动后留下的图像，以便在下一帧中重新绘制。
    oled_drawbmp_block_clear(pos + length, 6, speed);
		// 最后，更新仙人掌的位置，使其向左移动。
    pos = pos - speed;
    return pos + speed;
}

// 绘制跳跃小恐龙
int OLED_DrawDinoJump(char reset)
{
		// 存储了小恐龙跳跃时的速度变化
    char speed_arr[] = {1, 1, 3, 3, 4, 4, 5, 6, 7};
		// 这些静态变量分别用于存储当前速度索引、小恐龙的高度和跳跃方向。
    static char speed_idx = sizeof(speed_arr) - 1;
    static int height = 0;
    static char dir = 0;
    //char speed = 4;
		
		// 这些是函数内部使用的变量。j用于在循环中迭代，x和y用于表示坐标，offset用于计算小恐龙的位置偏移，byte用于存储要写入的字节。
    unsigned int j = 0;
    unsigned char x, y;
    char offset = 0;
    unsigned char byte;
		
		// 如果reset参数为1，函数将重置小恐龙的高度、方向和速度索引，并返回0。
    if(reset == 1)
    {
        height = 0;
        dir = 0;
        speed_idx = sizeof(speed_arr) - 1;
        return 0;
    }
		// 接下来的代码块处理小恐龙的跳跃动作，包括上升和下降两个阶段。它根据dir变量的值来决定小恐龙是上升还是下降，并相应地更新height和speed_idx。
    if (dir == 0)
    {
        height += speed_arr[speed_idx];
        speed_idx --;
        if (speed_idx < 0) speed_idx = 0;
    }
    if (dir == 1)
    {
        height -= speed_arr[speed_idx];
        speed_idx ++;
        if (speed_idx > sizeof(speed_arr) - 1) speed_idx = sizeof(speed_arr) - 1;
    }
    if(height >= 31)
    {
        dir = 1;
        height = 31;
    }
    if(height <= 0)
    {
        dir = 0;
        height = 0;
    }
    if(height <= 7) offset = 0;
    else if(height <= 15) offset = 1;
    else if(height <= 23) offset = 2;
    else if(height <= 31) offset = 3;
    else offset = 4;

		/* 这个循环是函数的核心部分，它在OLED屏幕上绘制跳跃的小恐龙。首先，它设置了OLED的位置，然后开始IIC通信，写入一些特定的字节并等待确认。
		 然后，它在一个内部循环中，根据height和当前的x和y值从DINO_JUMP数组中获取字节，并写入这个字节。最后，它停止IIC通信。
		 这个过程对每个y值重复三次，这可能表示小恐龙的图像是3行高。*/

    for(y = 0; y < 3; y++) // 4
    {
        OLED_Set_Pos(16, 5 - offset + y);

        IIC_Start();
        Write_IIC_Byte(0x78);
        IIC_Wait_Ack();
        Write_IIC_Byte(0x40);
        IIC_Wait_Ack();
        for (x = 0; x < 16; x++) // 32
        {
            j = y * 16 + x; // 32
            byte = DINO_JUMP[height % 8][j];

            Write_IIC_Byte(byte);
            IIC_Wait_Ack();
        }
        IIC_Stop();
    }
    if (dir == 0) oled_drawbmp_block_clear(16, 8 - offset, 16);
    if (dir == 1) oled_drawbmp_block_clear(16, 4 - offset, 16);
    return height;
}

// 绘制重启
void OLED_DrawRestart(void)
{
  OLED_DrawBMP(52, 2, 76, 5, RESTART);
  OLED_ShowString(10, 3, "GAME", 16);
  OLED_ShowString(86, 3, "OVER", 16);
}

// 绘制封面
void OLED_DrawCover(void)
{
  OLED_DrawBMP(0, 0, 128, 8, COVER);
}
